package com.alks.pad.controller.commom;

import com.alks.common.utils.beanutils.StringUtils;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.entity.exception.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.alks.entity.data.enums.ResultCodeEnum.*;

/**
 * 异常处理器
 *
 * @author MS
 */
@RestControllerAdvice
@Slf4j
public class ExceptionController {
    /**
     * 处理token异常
     *
     * @param e 异常
     * @return 返回503或者3
     */
    @ExceptionHandler(TokenErrorException.class)
    public ResponseInfo tokenException(TokenErrorException e) {
        String message = "无权访问";
        Integer code = TOKEN_ERROR.getCode();
        if ("token已过期".equals(e.getMessage())) {
            message = "登录验证超时，请重新登录";
            code = TOKEN_TIME_ERROR.getCode();
        }
        if (e.getMessage().endsWith("请重新登录")) {
            message = "登录验证失败，请重新登录";
        }
        log.info("Token异常已处理");
        return ResponseInfo.error(message, code);
    }

    /**
     * 处理token异常
     *
     * @param e 异常
     * @return 返回505
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseInfo httpReqMethodException(HttpRequestMethodNotSupportedException e) {
        return ResponseInfo.error("请求方式错误",METHOD_ERROR.getCode());
    }

    /**
     * 处理内部抛出异常
     *
     * @param e 异常
     * @return 返回504
     */
    @ExceptionHandler(ServiceErrorException.class)
    public ResponseInfo serviceException(ServiceErrorException e) {
        urlLogs();
        log.warn("服务错误：{}",e.getMessage());
        return ResponseInfo.error(e.getMessage(), SERVICE_ERROR.getCode());
    }

    /**
     * 处理前端返回参数异常
     *@param e 异常
     *@return 返回505
     */
    @ExceptionHandler({InDataException.class, MethodArgumentNotValidException.class,HttpMessageNotReadableException.class})
    public ResponseInfo inDataException(Exception e) {
        urlLogs();
        String message = "";
        if (e instanceof MethodArgumentNotValidException){
            message = Objects.requireNonNull(((MethodArgumentNotValidException) e)
                    .getBindingResult().getFieldError())
                    .getDefaultMessage();
        } else if (e instanceof InDataException) {
            message = e.getMessage();
        }else if (e instanceof HttpMessageNotReadableException){
            String fieldName = extractFieldNameFromException(e.getMessage());
            message = "错误的传参："+fieldName;
        }
        log.warn("传参错误：{}",e.getMessage());
        return ResponseInfo.error(message, INPUT_ERROR.getCode());
    }

    /**
     * 缺少必须数据异常
     *@param e 异常
     *@return 返回505
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseInfo missReq(MissingServletRequestParameterException e) {
        urlLogs();
        String[] split = e.getMessage().split("'");
        String message = "缺少必要数据"+split[1];
        log.warn("传参缺失：{}",e.getMessage());
        return ResponseInfo.error(message, INPUT_ERROR.getCode());
    }

    /**
     * 处理工具类抛出的异常
     *@param e 异常
     *@return 返回505
     */
    @ExceptionHandler(UtilsException.class)
    public ResponseInfo utilsException(Exception e) {
        urlLogs();
        log.warn("工具类异常：{}",e.getMessage());
        return ResponseInfo.error(e.getMessage(), INPUT_ERROR.getCode());
    }

    /**
     * 处理未知异常
     *
     * @param e 异常
     * @return 返回500
     */
    @ExceptionHandler(Exception.class)
    public ResponseInfo exception(Exception e) {
        urlLogs();
        String logMessage = e.getMessage();
        String returnMessage = "程序内部出现异常";
        log.warn("未知异常：{}\n", logMessage, e);
        return ResponseInfo.error(returnMessage, ERROR.getCode());
    }


    /**
     * 获取请求路径
     */
    private static void urlLogs() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String request = attributes.getRequest().getRequestURI();
        log.warn("报错路径：{}", request);
    }

    /**
     * 处理获得错误传参的字段
     * @param message 错误信息
     * @return 字段名
     */
    private String extractFieldNameFromException(String message) {
        Pattern pattern = Pattern.compile("\\[(\".*?\")\\]");
        Matcher matcher = pattern.matcher(message);
        if (matcher.find()) {
            // 移除外层的引号和方括号，返回纯字段名
            return matcher.group(1).replaceAll("\"", "");
        }
        // 如果没有找到合适的索引，则返回一个通用的错误信息或字段名
        return "未知字段";
    }

    /**
     * 导出异常
     * @param e 异常
     */
    @ExceptionHandler(HeaderException.class)
    public void serviceException(ServiceErrorException e, HttpServletResponse response) {
        urlLogs();
        log.warn("导出异常：{}",e.getMessage());
        response.setStatus(SERVICE_ERROR.getCode());
        response.setHeader("Io-Error-Message", e.getMessage());
    }

    @ExceptionHandler(EmptyDataException.class)
    public ResponseInfo emptyDataException(EmptyDataException e) {
        log.warn("查询数据为空：{}",e.getMessage());
        String msg = null;
        if (!StringUtils.isEmpty(e.getMessage())) {
            msg = "：" + e.getMessage();
        }
        return ResponseInfo.error(EMPTY_DATA.getMessage() + msg, EMPTY_DATA.getCode());
    }

    @ExceptionHandler(ParamErrorException.class)
    public ResponseInfo paramErrorException(ParamErrorException e) {
        log.warn("参数错误：{}",e.getMessage());
        String msg = null;
        if (!StringUtils.isEmpty(e.getMessage())) {
            msg = "：" + e.getMessage();
        }
        return ResponseInfo.error(PARAM_ERROR.getMessage() + msg, PARAM_ERROR.getCode());
    }

    @ExceptionHandler(FileException.class)
    public ResponseInfo fileErrorException(FileException e) {
        log.warn("文件服务错误：{}",e.getMessage());
        String msg = null;
        if (!StringUtils.isEmpty(e.getMessage())) {
            msg = "：" + e.getMessage();
        }
        return ResponseInfo.error(ERROR_FILE.getMessage() + msg, ERROR_FILE.getCode());
    }
}
